use codegraph_api::{WebSocketManager, GraphUpdateMessage, GraphUpdateType, GraphUpdateDetails, SubscriptionFilter};
use codegraph_core::PerformanceMonitor;
use std::collections::HashMap;
use std::sync::Arc;
use uuid::Uuid;

#[tokio::test]
async fn test_websocket_manager_creation() {
    let performance_monitor = Arc::new(PerformanceMonitor::new());
    let ws_manager = WebSocketManager::new(performance_monitor);
    
    let stats = ws_manager.get_connection_stats().await;
    assert_eq!(stats.total_connections, 0);
    assert_eq!(stats.authenticated_connections, 0);
    assert_eq!(stats.active_subscriptions, 0);
    
    println!("WebSocket manager created successfully");
    println!("Initial connection stats: {:?}", stats);
}

#[tokio::test]
async fn test_graph_update_message_creation() {
    let update_message = GraphUpdateMessage {
        id: Uuid::new_v4(),
        timestamp: std::time::SystemTime::now(),
        update_type: GraphUpdateType::NodeAdded,
        project_path: "/test/project".to_string(),
        details: GraphUpdateDetails {
            nodes: vec![Uuid::new_v4(), Uuid::new_v4()],
            edges: vec![Uuid::new_v4()],
            files: vec!["test.py".to_string()],
            summary: "Added new function".to_string(),
            metadata: HashMap::new(),
        },
        metrics: None,
    };
    
    println!("Graph update message created:");
    println!("  ID: {}", update_message.id);
    println!("  Type: {:?}", update_message.update_type);
    println!("  Project: {}", update_message.project_path);
    println!("  Summary: {}", update_message.details.summary);
    println!("  Nodes affected: {}", update_message.details.nodes.len());
    println!("  Edges affected: {}", update_message.details.edges.len());
    println!("  Files affected: {}", update_message.details.files.len());
    
    assert_eq!(update_message.details.nodes.len(), 2);
    assert_eq!(update_message.details.edges.len(), 1);
    assert_eq!(update_message.details.files.len(), 1);
}

#[tokio::test]
async fn test_subscription_filter() {
    let filter = SubscriptionFilter {
        node_types: Some(vec!["Function".to_string(), "Class".to_string()]),
        languages: Some(vec!["python".to_string(), "rust".to_string()]),
        file_patterns: Some(vec!["*.py".to_string(), "*.rs".to_string()]),
        project_paths: Some(vec!["/src".to_string(), "/tests".to_string()]),
    };
    
    println!("Subscription filter created:");
    println!("  Node types: {:?}", filter.node_types);
    println!("  Languages: {:?}", filter.languages);
    println!("  File patterns: {:?}", filter.file_patterns);
    println!("  Project paths: {:?}", filter.project_paths);
    
    assert!(filter.node_types.is_some());
    assert!(filter.languages.is_some());
    assert!(filter.file_patterns.is_some());
    assert!(filter.project_paths.is_some());
}

#[tokio::test]
async fn test_broadcast_update() {
    let performance_monitor = Arc::new(PerformanceMonitor::new());
    let ws_manager = WebSocketManager::new(performance_monitor);
    
    let update_message = GraphUpdateMessage {
        id: Uuid::new_v4(),
        timestamp: std::time::SystemTime::now(),
        update_type: GraphUpdateType::FileChanged,
        project_path: "/test/project".to_string(),
        details: GraphUpdateDetails {
            nodes: vec![],
            edges: vec![],
            files: vec!["modified_file.py".to_string()],
            summary: "File content changed".to_string(),
            metadata: HashMap::new(),
        },
        metrics: None,
    };
    
    // Test broadcasting (no connections to receive it, but should not error)
    let result = ws_manager.broadcast_update(update_message.clone()).await;
    assert!(result.is_ok(), "Broadcasting should succeed even with no connections");
    
    println!("Broadcast update test completed");
    println!("  Update ID: {}", update_message.id);
    println!("  Broadcast result: {:?}", result);
}

#[tokio::test]
async fn test_multiple_update_types() {
    let performance_monitor = Arc::new(PerformanceMonitor::new());
    let ws_manager = WebSocketManager::new(performance_monitor);
    
    let update_types = vec![
        GraphUpdateType::NodeAdded,
        GraphUpdateType::NodeUpdated,
        GraphUpdateType::NodeRemoved,
        GraphUpdateType::EdgeAdded,
        GraphUpdateType::EdgeUpdated,
        GraphUpdateType::EdgeRemoved,
        GraphUpdateType::FileChanged,
        GraphUpdateType::ProjectRebuilt,
        GraphUpdateType::RelationshipsUpdated,
    ];
    
    for (i, update_type) in update_types.iter().enumerate() {
        let update_message = GraphUpdateMessage {
            id: Uuid::new_v4(),
            timestamp: std::time::SystemTime::now(),
            update_type: update_type.clone(),
            project_path: format!("/test/project_{}", i),
            details: GraphUpdateDetails {
                nodes: vec![Uuid::new_v4()],
                edges: vec![Uuid::new_v4()],
                files: vec![format!("file_{}.py", i)],
                summary: format!("Test update type: {:?}", update_type),
                metadata: HashMap::new(),
            },
            metrics: None,
        };
        
        let result = ws_manager.broadcast_update(update_message).await;
        assert!(result.is_ok(), "Broadcasting update type {:?} should succeed", update_type);
    }
    
    println!("Multiple update types test completed");
    println!("  Tested {} different update types", update_types.len());
}

#[tokio::test]
async fn test_connection_stats_tracking() {
    let performance_monitor = Arc::new(PerformanceMonitor::new());
    let ws_manager = WebSocketManager::new(performance_monitor);
    
    // Initial stats should be empty
    let initial_stats = ws_manager.get_connection_stats().await;
    assert_eq!(initial_stats.total_connections, 0);
    assert_eq!(initial_stats.authenticated_connections, 0);
    assert_eq!(initial_stats.active_subscriptions, 0);
    
    println!("Connection stats tracking test:");
    println!("  Initial stats: {:?}", initial_stats);
    
    // Note: Testing actual connections would require setting up WebSocket clients,
    // which is complex in a unit test environment. The framework is in place
    // and would be tested in integration tests.
}

#[tokio::test]
async fn test_update_details_serialization() {
    let details = GraphUpdateDetails {
        nodes: vec![Uuid::new_v4(), Uuid::new_v4()],
        edges: vec![Uuid::new_v4()],
        files: vec!["main.py".to_string(), "user.py".to_string()],
        summary: "Added new user class and main function".to_string(),
        metadata: {
            let mut map = HashMap::new();
            map.insert("language".to_string(), serde_json::json!("python"));
            map.insert("complexity".to_string(), serde_json::json!(5));
            map.insert("lines_added".to_string(), serde_json::json!(42));
            map
        },
    };
    
    // Test serialization
    let serialized = serde_json::to_string(&details);
    assert!(serialized.is_ok(), "Update details should serialize successfully");
    
    let json_str = serialized.unwrap();
    println!("Update details serialization test:");
    println!("  JSON length: {} characters", json_str.len());
    println!("  Contains nodes: {}", json_str.contains("function_main"));
    println!("  Contains metadata: {}", json_str.contains("language"));
    
    // Test deserialization
    let deserialized: Result<GraphUpdateDetails, _> = serde_json::from_str(&json_str);
    assert!(deserialized.is_ok(), "Update details should deserialize successfully");
    
    let restored_details = deserialized.unwrap();
    assert_eq!(restored_details.nodes.len(), 2);
    assert_eq!(restored_details.edges.len(), 1);
    assert_eq!(restored_details.files.len(), 2);
    assert_eq!(restored_details.summary, "Added new user class and main function");
    assert_eq!(restored_details.metadata.len(), 3);
}

#[tokio::test]
async fn test_subscription_filter_serialization() {
    let filter = SubscriptionFilter {
        node_types: Some(vec!["Function".to_string(), "Class".to_string(), "Variable".to_string()]),
        languages: Some(vec!["python".to_string(), "rust".to_string(), "javascript".to_string()]),
        file_patterns: Some(vec!["*.py".to_string(), "*.rs".to_string(), "*.js".to_string()]),
        project_paths: Some(vec!["/src".to_string(), "/tests".to_string(), "/examples".to_string()]),
    };
    
    // Test serialization
    let serialized = serde_json::to_string(&filter);
    assert!(serialized.is_ok(), "Subscription filter should serialize successfully");
    
    let json_str = serialized.unwrap();
    println!("Subscription filter serialization test:");
    println!("  JSON length: {} characters", json_str.len());
    
    // Test deserialization
    let deserialized: Result<SubscriptionFilter, _> = serde_json::from_str(&json_str);
    assert!(deserialized.is_ok(), "Subscription filter should deserialize successfully");
    
    let restored_filter = deserialized.unwrap();
    assert_eq!(restored_filter.node_types.as_ref().unwrap().len(), 3);
    assert_eq!(restored_filter.languages.as_ref().unwrap().len(), 3);
    assert_eq!(restored_filter.file_patterns.as_ref().unwrap().len(), 3);
    assert_eq!(restored_filter.project_paths.as_ref().unwrap().len(), 3);
}

#[tokio::test]
async fn test_websocket_manager_with_performance_integration() {
    let performance_monitor = Arc::new(PerformanceMonitor::new());
    
    // Record some performance metrics
    performance_monitor.record_parse_operation(
        std::time::Duration::from_millis(100),
        1024,
        "python".to_string(),
        true,
        50,
        None,
    ).await.expect("Failed to record parse operation");
    
    let ws_manager = WebSocketManager::new(performance_monitor.clone());
    
    // Create an update with performance metrics
    let update_message = GraphUpdateMessage {
        id: Uuid::new_v4(),
        timestamp: std::time::SystemTime::now(),
        update_type: GraphUpdateType::NodeAdded,
        project_path: "/test/project".to_string(),
        details: GraphUpdateDetails {
            nodes: vec![Uuid::new_v4()],
            edges: vec![],
            files: vec!["new_file.py".to_string()],
            summary: "Added new function with performance tracking".to_string(),
            metadata: HashMap::new(),
        },
        metrics: Some(codegraph_api::UpdateMetrics {
            duration_ms: 100,
            nodes_processed: 1,
            edges_processed: 0,
            memory_usage_mb: 2.5,
        }),
    };
    
    let result = ws_manager.broadcast_update(update_message.clone()).await;
    assert!(result.is_ok(), "Broadcasting with performance metrics should succeed");
    
    println!("WebSocket-Performance integration test:");
    println!("  Update with metrics broadcasted successfully");
    println!("  Duration: {}ms", update_message.metrics.as_ref().unwrap().duration_ms);
    println!("  Memory usage: {}MB", update_message.metrics.as_ref().unwrap().memory_usage_mb);
}
